﻿using EasyDDD.AdminModule.Domain.AggregateSysMenu;
using EasyDDD.AdminModule.Records;
using EasyDDD.AdminModule.Repository;
using EasyDDD.Infrastructure;
using EasyDDD.Infrastructure.EFCore.Repository;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
// using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.IdentityModel.Tokens;
using StackExchange.Redis;
using System.Reflection;
using System.Security.Claims;
using System.Text;

namespace EasyDDD.AdminModule.Application
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddAdminModule(this IServiceCollection services, IConfiguration configuration)
        {
            var moduleName = "AdminModule";

            Console.WriteLine("moduleName {0}", moduleName);
            Console.WriteLine("Assembly.GetCallingAssembly().FullName:{0}", Assembly.GetCallingAssembly().FullName);
            Console.WriteLine("Assembly.GetEntryAssembly().FullName:{0}", Assembly.GetEntryAssembly()?.FullName);
            Console.WriteLine("Assembly.GetExecutingAssembly().FullName:{0}", Assembly.GetExecutingAssembly().FullName);

            if (moduleName != null && configuration.GetSection(moduleName).Exists())
            {
                configuration = configuration.GetSection(moduleName);
            }


            services.AddAutoMapper(typeof(AutoMapperProfile));
            services.AddFluentValidationAutoValidation();
            services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());

            services.AddRepository<AdminModuleRepositoryDbContext>()
                .AddDbContext<AdminModuleRepositoryDbContext>(o => o.UseNpgsql(configuration.GetConnectionString("PostgreSQL")));
            services.AddRecords<AdminModuleRecordsDbContext>()
                .AddDbContext<AdminModuleRecordsDbContext>(o => o.UseNpgsql(configuration.GetConnectionString("PostgreSQL")));

            services.AddMediatR(cfg =>
            {
                cfg.RegisterServicesFromAssemblies(Assembly.GetExecutingAssembly());
                cfg.AddOpenBehavior(typeof(CommandUnitOfWorkBehavior<,>));
            });
            services.AddCap(o =>
            {
                o.UseEntityFramework<AdminModuleRepositoryDbContext>();
                //o.UseRabbitMQ(cfg => configuration.GetSection("RabbitMQ").Bind(cfg));
                o.UseRedis(cfg => configuration.GetSection("ConnectionStrings:Redis").Bind(cfg));
                o.UseDashboard();
            });

            services.AddScoped<IUnitOfWork>(p => p.GetRequiredService<AdminModuleRepositoryDbContext>());
            services.AddIntegrationEventHandler();

            services.AddDomainSevice<Domain.DomainAssemblyLoadMark>();
            // TODO 这个反射注入怎么搞 用不到了
            services.TryAddScoped<IRepository<SysMenu, SysMenuId>, SysMenuRepository>();

            //services.AddIdentity<Domain.SysAdminAggregate.ApplicationUser, Domain.SysAdminRoleAggregate.ApplicationRole>
            //(options =>
            //{
            //    // Password settings.
            //    options.Password.RequireDigit = true;
            //    options.Password.RequireLowercase = true;
            //    options.Password.RequireUppercase = false;
            //    options.Password.RequireNonAlphanumeric = false;
            //    options.Password.RequiredLength = 6;
            //    options.Password.RequiredUniqueChars = 1;

            //    // Lockout settings.
            //    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
            //    options.Lockout.MaxFailedAccessAttempts = 5;
            //    options.Lockout.AllowedForNewUsers = true;

            //    // User settings.
            //    //options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
            //    options.User.RequireUniqueEmail = false;

            //}).AddEntityFrameworkStores<AdminModuleRepositoryDbContext>().AddDefaultTokenProviders();

            //services.AddIdentity<Domain.SysAdminAggregate.ApplicationUser, Domain.SysAdminRoleAggregate.ApplicationRole>();

            services.AddAuthorization();
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                //options.TokenValidationParameters = new TokenValidationParameters()
                //{
                //    ValidateIssuer = true, //是否验证Issuer
                //    //ValidIssuer = configuration["Jwt:Issuer"], //发行人Issuer
                //    ValidateAudience = true, //是否验证Audience
                //    //ValidAudience = configuration["Jwt:Audience"], //订阅人Audience
                //    ValidateIssuerSigningKey = true, //是否验证SecurityKey
                //    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Secret"]!)), //SecurityKey
                //    ValidateLifetime = true, //是否验证失效时间
                //    ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值，解决服务器端时间不同步问题（秒）
                //    RequireExpirationTime = true,
                //};
                //*************************//
                options.RequireHttpsMetadata = false;
                options.SaveToken = true;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration.GetValue<string>("JWT:Secret")!)),//JWT秘钥
                    //ValidIssuer = configuration.GetValue<string>("JWT:ISyouuser"),//发行者,
                    //ValidAudience = configuration.GetValue<string>("JWT:IsAudience"),//接收者,
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    // 是否验证Token有效期，使用当前时间与Token的Claims中的NotBefore和Expires对比
                    ValidateLifetime = true,
                    //注意这是缓冲过期时间，总的有效时间等于这个时间加上jwt的过期时间，如果不配置，默认是5分钟
                    ClockSkew = TimeSpan.Zero
                };
            });

            return services;
        }
    }
}
